Architecture
web3agent is built around a single core idea: every blockchain capability should be accessible in two ways. AI agents running inside tools like Claude Code or Cursor reach it through the MCP protocol. Downstream TypeScript projects reach it by importing from the npm package directly. Both paths share the same underlying runtime, the same validation logic, and the same error handling.
This is the two-layer architecture.
The Two Layers
MCP Tool Layer
The MCP Tool Layer lives in src/tools/. It exposes blockchain capabilities as named tools that any MCP-compatible AI agent can discover and call. Tools are grouped by domain and registered in src/tools/<group>/index.ts.
When an AI agent connects to web3agent via npx web3agent, it gets a stdio MCP server. The agent can list all available tools, read their descriptions and input schemas, and invoke them by name with JSON arguments. The server validates inputs, executes the operation, and returns a structured result.
Programmatic SDK Layer
The SDK Layer lives in src/api/ and is exported from src/index.ts. It's for TypeScript projects that want to call web3agent functions directly, without running an MCP server.
SDK functions are thin wrappers. Each one calls getRuntime() to get a shared runtime instance, then calls invokeAndRequireData() to run the underlying tool and extract the typed result. If the tool returns an error, invokeAndRequireData() throws a Web3AgentError. If it succeeds, you get back a fully typed response.
// SDK usage — import and call directly
import { getSwapQuote } from "web3agent";
const quote = await getSwapQuote({
fromToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
toToken: "0x4200000000000000000000000000000000000006", // WETH on Base
fromAmount: "100000000", // 100 USDC (6 decimals)
chainId: 8453,
});
Data Flow
MCP Tool Call
SDK Call
Source Structure
web3agent/src/
├── index.ts # Root public API exports (590+ lines)
├── cli.ts # CLI entry (init, policy, server commands)
│
├── runtime/ # MCP Runtime Layer
│ ├── managed-runtime.ts # Core runtime: tool registry, invocation, health
│ ├── server.ts # MCP protocol server (stdio transport)
│ ├── startup.ts # Server startup + graceful shutdown
│ └── default.ts # Default runtime singleton
│
├── api/ # SDK Layer (programmatic API)
│ ├── shared.ts # getRuntime(), invokeAndRequireData(), createSDKInvoker()
│ ├── types.ts # All SDK input/output types
│ ├── errors.ts # Web3AgentError class
│ ├── swaps.ts # getSwapQuote, executeSameChainSwap, getSwapHistory
│ ├── intents.ts # prepareSwapIntent, prepareOrderIntent, prepareBridgeIntent
│ ├── orders.ts # listOrders, placeOrder, cancelOrder
│ ├── explorer.ts # 40+ blockchain data functions
│ ├── market.ts # 20+ market data functions
│ ├── research.ts # 10+ research functions
│ └── ... # acp, agdp, erc8004, x402, policy, simulation
│
├── tools/ # MCP Tool Layer
│ ├── register.ts # ToolDefinition interface + tool definitions
│ ├── orbs/ # 15+ tools: quotes, swaps, orders, intents, TWAP, Spot
│ ├── lifi/ # 3 tools: bridge quotes, execution, intents
│ ├── explorer/ # 40+ tools: accounts, transactions, tokens, contracts
│ ├── evm/ # 30+ tools: contract interaction, transfers, ENS, gas
│ ├── market/ # 20+ tools: TVL, prices, volumes, sentiment
│ ├── research/ # 10+ tools: security, yields, holders, governance
│ └── ... # wallet, tokens, operations, agdp, acp, erc8004, x402
│
├── chains/registry.ts # Viem chain registry (17 chains)
├── wallet/ # Wallet management (persistence, confirmation, audit)
├── config/env.ts # Environment variable parsing
├── tokens/ # Token resolver + registry + pricing
├── orbs/ # Orbs integration (Liquidity Hub, TWAP, Spot)
├── lifi/ # LI.FI bridge integration
├── evm/ # EVM provider (viem)
└── policy/ # Treasury policy engine + spend tracking
Package Entry Points
web3agent ships multiple entry points so you only import what you need.
| Entry Point | Import Path | What You Get |
|---|---|---|
| Root SDK | "web3agent" | All SDK functions, types, schemas, config helpers |
| Runtime | "web3agent/runtime" | createRuntime(), Web3AgentRuntime type |
| MCP Server | "web3agent/mcp" | ProxyServer, startServer() |
| aGDP | "web3agent/agdp" | aGDP marketplace API client |
| X-402 | "web3agent/x402" | X-402 payment protocol client |
Most downstream projects only need "web3agent" for SDK functions or "web3agent/runtime" when they want direct tool invocation with a custom runtime configuration.
Supported Chains
web3agent supports 17 EVM chains out of the box. The default is Base (8453). Override it with the CHAIN_ID environment variable or pass chainId per call.
| Chain | ID |
|---|---|
| Ethereum | 1 |
| Base | 8453 |
| Arbitrum | 42161 |
| Optimism | 10 |
| Polygon | 137 |
| Linea | 59144 |
| BSC | 56 |
| Avalanche | 43114 |
| zkSync Era | 324 |
| Scroll | 534352 |
| Mode | 34443 |
| Blast | 81457 |
| Mantle | 5000 |
| Celo | 42220 |
| Gnosis | 100 |
| Sepolia | 11155111 |
| Base Sepolia | 84532 |
Key Integrations
The tool layer aggregates multiple blockchain protocols behind a single namespace.
| Integration | Tool Prefix | Capabilities |
|---|---|---|
| Orbs | orbs_ | Liquidity Hub swaps, dTWAP, dLIMIT, Spot orders |
| LI.FI | lifi_ | Cross-chain bridges and swaps (20+ chains) |
| GOAT SDK | varies | Uniswap, Balancer, ERC-20/721, ENS, DexScreener, 0x, CoinGecko |
| Blockscout | blockscout_ | Indexed blockchain data (addresses, txs, NFTs, ABIs) |
| EVM | evm_ | Live on-chain state (balances, reads, writes, gas, ENS) |
| ACP | acp_ | Agent Cooperation Protocol (Virtuals ACPRouter) |
| aGDP | agdp_ | Agent marketplace (Virtuals Protocol) |
| ERC-8004 | erc8004_ | On-chain agent identity and reputation |
| X-402 | x402_ | HTTP-native stablecoin payments for agents |
Design Principles
stdout is reserved. The MCP protocol communicates over stdio. All internal logging goes to process.stderr.write() with a [module-name] prefix. Nothing should ever write to stdout except MCP protocol messages.
Zod is the single source of truth. Every tool's input schema is defined in Zod, then converted to JSON Schema for MCP registration. The same Zod schema validates runtime inputs. All fields carry .describe() annotations so AI agents can understand what each parameter does.
ESM only. All imports use .js extensions. The package ships as ESM with TypeScript declaration files.
Catch unknown, always. Error handling follows catch (e: unknown) throughout. No bare catches, no @ts-ignore.